#pragma once
#include<cstddef>
#include<iostream>
#include<ostream>
#include<queue>
#include<cassert>
#include<pthread.h>
#include<unistd.h>
#include"lock.hpp"
using std::queue;
using std::cout;
using std::endl;
#define THREADNUM 5//线程数

template<class T>
class threadPool{
    public:
        //双重检查锁定（Double-Check Locking）模拟实现线程池的单例模式，确保只有一个threadPool实例被创建。
        static threadPool<T>* getInstance()//获取单例实例的静态方法
        {
            static Mutex mutex;//静态局部变量，确保线程安全初始化，缘于C++中静态局部变量的特性，保证只有其在首次访问时才会被初始化
                               //即如果多个线程同时到达静态局部变量的初始化语句，只会有一个线程执行初始化，其他线程会等待初始化完成。
                               //意味着锁对象不会在程序启动时就被创建，而是直到第一个线程尝试获取单例实例时才会创建，减少了资源消耗
                               //通过使用静态局部变量，无需手动管理锁对象的生命周期或担心它的初始化顺序问题。这使得代码更加简洁且易于维护。
                               //如果没有使用静态局部变量，而是在每次检查 _instance 是否为 nullptr 之前都创建一个新的 Mutex 对象，
                               //那么每次都会产生一个新的锁对象，这不仅浪费资源，还可能导致不必要的性能开销。
                               //使用静态局部变量可以确保在整个程序运行期间只有一个 Mutex 实例用于保护单例的初始化过程。

            if(_instance==nullptr)//第一次检查，如果实例存在则直接返回
            {
                LockGuard lockG(&mutex);//上锁，确保只有一个线程可以进入
                if(_instance==nullptr)//在被锁保护的情况下进行第二次检查
                {
                    _instance=new threadPool<T>();//创建单例实例
                }
            }
            return _instance;
        }
        static void* threadRountine(void* args)//回调函数，每个线程都要执行的函数，只能设为静态的
        {                                      //先让自己进入分离状态，然后进入一个无限循环，在其中等待任务队列中有任务可以处理
            pthread_detach(pthread_self());//分离后自动回收
            threadPool<T>* tP=static_cast<threadPool<T>*>(args);
            while(true)
            {
                tP->lockQueue();
                while(!tP->haveTask())
                {
                    tP->waitForTask();
                }
                T task=tP->popTask();
                tP->unlockQueue();
                task.run();
            }
        }
        void start()//启动线程池，创建指定数量的工作线程，并将它们设置为工作状态
        {
            try{//利用try-catch块捕捉抛出的异常
                if(_isStart)
                    throw"Error: thread pool already exists";
            }
            catch(const char* e)
            {
                cout<<e<<endl;
                return;
            }
            for(int i=0;i<_threadNum;i++)
            {
                pthread_t temp;
                pthread_create(&temp,nullptr,threadRountine,this);
            }
            _isStart=true;
        }
        void pushTask(const T& in)//将新任务添加到任务队列中，并通知一个等待的任务处理器。
        {
            lockQueue();//加锁处理保证对于共享资源的访问时安全的。
            _taskQueue.push(in);//添加任务
            choiceThreadForHandler();//唤醒线程去处理任务
            unlockQueue();//解锁
        }

        int getThreadNum()
        {
            return _threadNum;
        }
        ~threadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }
        threadPool(const threadPool<T>&)=delete;//禁止拷贝构造和赋值操作
        threadPool<T>& operator=(const threadPool<T>&)=delete;
    private:
        threadPool(size_t threadNum=THREADNUM)//构造函数私有，防止外部实例化。
            :_threadNum(threadNum)            //初始化线程池的基本属性，线程数量、是否已启动、互斥锁和条件变量
             ,_isStart(false){
             assert(_threadNum>0);

             pthread_mutex_init(&_mutex,nullptr);
             pthread_cond_init(&_cond,nullptr);
             }
        void lockQueue()
        {
            pthread_mutex_lock(&_mutex);
        }
        void unlockQueue()
        {
            pthread_mutex_unlock(&_mutex);
        }
        bool haveTask()//检查任务队列中是否有待处理任务
        {
            return !_taskQueue.empty();
        }
        void waitForTask()//条件变量等待
        {
            pthread_cond_wait(&_cond,&_mutex);
        }
        T popTask()//移除处理完成的任务
        {
            T task=_taskQueue.front();
            _taskQueue.pop();
            return task;
        }
        void choiceThreadForHandler()//当有新的任务被添加到任务队列时，通过该函数去通知一个闲的线程去处理新任务。
        {
            pthread_cond_signal(&_cond);//唤醒线程
        }
    private:
        size_t _threadNum;//线程数
        bool _isStart;//线程池是否已启动
        queue<T> _taskQueue;//任务队列，属于共享资源
        pthread_mutex_t _mutex;//锁
        pthread_cond_t _cond;//条件变量

        static threadPool<T>* _instance;//单例模式中的唯一一个静态变量，用来保存类的唯一实例的指针。          
};

template<class T>
threadPool<T>* threadPool<T>::_instance=nullptr;//该指针必须在类外面初始化为nullptr;